Immutable 객체

AI
qwen-3-235b-a22b-instruct-2507
작성자
익명
작성일
2025.09.02
조회수
7
버전
v1

Immutable 객체

개요

Immutable 객체(불변 객체)는 객체지향프로그래밍(OOP)에서 중요한 개념 중 하나로, 객체가 생성된 이후 그 내부 상태를 변경할 수 없는 객체를 의미합니다. 즉, Immutable 객체는 초기화된 후 어떤 메서드도 내부 데이터를 수정하지 않으며, 상태 변경이 필요한 경우 기존 객체를 수정하는 대신 새로운 객체를 생성하여 반환합니다. 이는 프로그램의 안정성, 스레드 안정성(thread safety), 디버깅 용이성, 그리고 함수형 프로그래밍과의 호환성 측면에서 큰 장점을 제공합니다.

Immutable 객체는 Java, Python, C#, Kotlin 등 다양한 객체지향 언어에서 활용되며, 특히 동시성 프로그래밍(concurrent programming)과 함수형 프로그래밍 패러다임에서 핵심적인 역할을 합니다.


Immutable 객체의 특징

Immutable 객체는 다음과 같은 주요 특징을 가집니다:

  • 상태 변경 불가: 객체 생성 후 필드 값이 변경되지 않음.
  • 스레드 안전성: 공유 데이터가 변경되지 않기 때문에 멀티스레드 환경에서 안전하게 사용 가능.
  • 해시 기반 컬렉션에 적합: 해시 값이 변하지 않아 [HashMap](/doc/%EA%B8%B0%EC%88%A0/%EC%9E%90%EB%B0%94/%EC%BB%AC%EB%A0%89%EC%85%98%20%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC/HashMap), [HashSet](/doc/%EA%B8%B0%EC%88%A0/%EC%9E%90%EB%B0%94/%EC%BB%AC%EB%A0%89%EC%85%98%20%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC/HashSet) 등에 안전하게 사용 가능.
  • 캐싱 및 재사용 용이: 동일한 상태의 객체는 캐싱하여 재사용할 수 있음.
  • 예측 가능한 동작: 객체의 상태가 변하지 않기 때문에 디버깅과 테스트가 쉬움.

Immutable 객체의 예시

Java에서의 Immutable 객체

Java에서는 [String](/doc/%EA%B8%B0%EC%88%A0/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/%EC%9E%90%EB%A3%8C%ED%98%95/String), [Integer](/doc/%EA%B8%B0%EC%88%A0/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/%EC%9E%90%EB%A3%8C%ED%98%95/Integer), [LocalDateTime](/doc/%EA%B8%B0%EC%88%A0/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/%EC%9E%90%EB%A3%8C%ED%98%95/LocalDateTime) 등이 대표적인 Immutable 클래스입니다.

String str = "Hello";
str = str.concat(" World"); // 새로운 String 객체를 생성

위 코드에서 concat() 메서드는 기존 str 객체를 수정하지 않고, "Hello World"를 담은 새로운 String 객체를 반환합니다. 이는 String 클래스가 내부적으로 final 필드를 사용하고, 모든 상태 변경 메서드가 새로운 인스턴스를 반환하도록 설계되어 있기 때문입니다.

사용자 정의 Immutable 클래스를 작성하는 예시:

public final class Person {
    private final String name;
    private final int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    // 상태 변경이 필요한 경우 새로운 객체 생성
    public Person withAge(int newAge) {
        return new Person(this.name, newAge);
    }
}

  • final class: 상속 불가능하게 하여 하위 클래스에서 상태를 변경하는 것을 방지.
  • private final 필드: 내부 상태 변경 불가.
  • 게터만 제공, 세터 미제공.
  • 상태 변경이 필요한 경우 withAge()처럼 새로운 객체를 반환하는 메서드 제공 (Fluent API 스타일).

Immutable 객체의 장점

장점 설명
스레드 안전성 객체가 변경되지 않기 때문에 여러 스레드가 동시에 접근해도 데이터 경합(race condition) 발생하지 않음.
예측 가능한 상태 객체의 상태가 생성 후 변하지 않아, 디버깅과 테스트가 용이함.
캐싱 및 재사용 동일한 값을 가진 객체는 캐싱하여 메모리 사용을 최적화할 수 있음 (예: String Pool).
함수형 프로그래밍과의 호환성 순수 함수(pure function)와 잘 어울림. 상태 부작용(side effect) 없음.
컬렉션의 키로 사용 가능 해시 값이 변하지 않으므로 HashMap의 키로 안전하게 사용 가능.

Immutable 객체의 단점

  • 성능 오버헤드: 상태 변경 시마다 새로운 객체를 생성하므로, 빈번한 변경이 발생하면 메모리 사용량과 GC(Garbage Collection) 부담이 증가할 수 있음.
  • 복잡한 객체 구조에서는 불편: 내부에 컬렉션을 포함하는 경우, 해당 컬렉션도 불변으로 관리해야 함.
  • 일부 언어에서는 지원 부족: 모든 언어가 Immutable 객체를 쉽게 만들 수 있는 기능을 제공하지는 않음.

Immutable 객체와 Mutable 객체 비교

구분 Immutable 객체 Mutable 객체
상태 변경 불가능 가능
스레드 안전성 높음 낮음 (동기화 필요)
메모리 사용 변경 시 새 객체 생성 → 더 큼 기존 객체 재사용 → 작음
사용 예시 String, LocalDateTime [StringBuilder](/doc/%EA%B8%B0%EC%88%A0/%EC%9E%90%EB%B0%94/%EB%AC%B8%EC%9E%90%EC%97%B4%20%EC%B2%98%EB%A6%AC/StringBuilder), [ArrayList](/doc/%EA%B8%B0%EC%88%A0/%EC%9E%90%EB%B0%94/%EC%BB%AC%EB%A0%89%EC%85%98%20%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC/ArrayList)

언어별 Immutable 객체 지원

  • Java: final 키워드, 불변 클래스 설계, [Collections.unmodifiableList](/doc/%EA%B8%B0%EC%88%A0/%EC%9E%90%EB%B0%94/%EC%BB%AC%EB%A0%89%EC%85%98%20%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC/Collections.unmodifiableList)() 등 제공.
  • Python: [tuple](/doc/%EA%B8%B0%EC%88%A0/%ED%8C%8C%EC%9D%B4%EC%8D%AC/%EC%9E%90%EB%A3%8C%ED%98%95/tuple), [frozenset](/doc/%EA%B8%B0%EC%88%A0/%ED%8C%8C%EC%9D%B4%EC%8D%AC/%EC%9E%90%EB%A3%8C%ED%98%95/frozenset), str은 불변. 사용자 정의 클래스는 [__slots__](/doc/%EA%B8%B0%EC%88%A0/%ED%8C%8C%EC%9D%B4%EC%8D%AC/%ED%81%B4%EB%9E%98%EC%8A%A4%20%EC%B5%9C%EC%A0%81%ED%99%94/__slots__)와 프로퍼티로 제어 가능.
  • C#: [readonly](/doc/%EA%B8%B0%EC%88%A0/C%23/%EB%B6%88%EB%B3%80%EC%84%B1/readonly), record 타입(특히 record struct)을 통해 불변성 지원.
  • Kotlin: [val](/doc/%EA%B8%B0%EC%88%A0/%EC%BD%94%ED%8B%80%EB%A6%B0/%EB%B3%80%EC%88%98%20%EC%84%A0%EC%96%B8/val) 선언, [data class](/doc/%EA%B8%B0%EC%88%A0/%EC%BD%94%ED%8B%80%EB%A6%B0/%ED%81%B4%EB%9E%98%EC%8A%A4%20%EC%84%A4%EA%B3%84/data%20class)와 함께 불변성 강조.

참고 자료 및 관련 문서


Immutable 객체는 현대 소프트웨어 개발에서 안정성과 유지보수성을 높이는 핵심 개념입니다. 특히 대규모 시스템이나 동시성 환경에서는 반드시 고려해야 할 설계 원칙 중 하나입니다. 객체의 상태를 변경하지 않고 새로운 객체를 생성함으로써, 예기치 않은 부작용을 방지하고 코드의 명확성을 높일 수 있습니다.

AI 생성 콘텐츠 안내

이 문서는 AI 모델(qwen-3-235b-a22b-instruct-2507)에 의해 생성된 콘텐츠입니다.

주의사항: AI가 생성한 내용은 부정확하거나 편향된 정보를 포함할 수 있습니다. 중요한 결정을 내리기 전에 반드시 신뢰할 수 있는 출처를 통해 정보를 확인하시기 바랍니다.

이 AI 생성 콘텐츠가 도움이 되었나요?